﻿using Furion.DependencyInjection;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Pear.Web.Core
{
    /// <summary>
    /// 系统信息 操作类
    /// 部分代码借鉴 YiShaAdmin  https://github.com/liukuo362573/YiShaAdmin/blob/master/YiSha.Util/YiSha.Util/ComputerHelper.cs
    /// </summary>
    public class SystemUtil : ITransient
    {

        public SystemUtil()
        {

        }

        private MemoryMetrics _MemoryMetrics;
        public MemoryMetrics MemoryMetrics
        {
            get
            {
                if (_MemoryMetrics == null)
                {
                    _MemoryMetrics = MemoryClient.GetMetrics();
                }
                return _MemoryMetrics;
            }
        }

        private MemoryMetricsClient _MemoryClient;
        public MemoryMetricsClient MemoryClient
        {
            get
            {
                if (_MemoryClient == null)
                {
                    _MemoryClient = new MemoryMetricsClient();

                }
                return _MemoryClient;
            }
        }



        /// <summary>
        /// 获取总内存数量
        /// </summary>
        /// <returns></returns>
        public string GetTotalRAM()
        {
            return Math.Ceiling(MemoryMetrics.Total / 1024).ToString() + " GB";
        }

        /// <summary>
        /// 获取内存使用率
        /// </summary>
        /// <returns></returns>
        public string GetRAMRate()
        {
            return Math.Ceiling(100 * MemoryMetrics.Used / MemoryMetrics.Total).ToString() + " %";
        }


        /// <summary>
        /// 获取.net内存占用
        /// </summary>
        /// <returns></returns>
        public string GetDotNetRAM()
        {
            return ((Double)Process.GetCurrentProcess().WorkingSet64 / 1048576).ToString("N2") + " MB";
        }


        /// <summary>
        /// 获取CPU使用率
        /// </summary>
        /// <returns></returns>
        public string GetCPURate()
        {
            string cpuRate = string.Empty;
            if (MemoryClient.IsUnix())
            {
                string output = MemoryClient.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'");
                cpuRate = $"{output.Trim()} %" ;
            }
            else
            {
                string output = MemoryClient.Cmd("wmic", "cpu get LoadPercentage");
                cpuRate = $"{output.Replace("LoadPercentage", string.Empty).Trim()} %";
            }
            return cpuRate;
        }

        /// <summary>
        /// 获取系统运行时长
        /// </summary>
        /// <returns></returns>
        public string  GetRunTime()
        {
            string runTime = string.Empty;
            try
            {
                runTime = FormatTime(Convert.ToInt64((DateTime.Now - GetStartupTime()).TotalMilliseconds.ToString().Split('.')[0]));
            }
            catch (Exception ex)
            {
               
            }
            return runTime;
        }

        /// <summary>
        /// 获取系统启动时间
        /// </summary>
        /// <returns></returns>
        public DateTime GetStartupTime()
        {
            DateTime startupTime = DateTime.Now;
            try
            {
                if (MemoryClient.IsUnix())
                {
                    string output = MemoryClient.Bash("uptime -s");
                    startupTime = ParseToDateTime(output.Trim());
                }
                else
                {
                    string output = MemoryClient.Cmd("wmic", "OS get LastBootUpTime/Value");
                    string[] outputArr = output.Split("=", StringSplitOptions.RemoveEmptyEntries);
                    if (outputArr.Length == 2)
                    {
                        startupTime = ParseToDateTime( outputArr[1].Split('.')[0]);
                    }
                }
            }
            catch (Exception ex)
            {

            }
            return startupTime;
        }


        /// <summary>
        /// 毫秒转天时分秒
        /// </summary>
        /// <param name="ms"></param>
        /// <returns></returns>
        private  string FormatTime(long ms)
        {
            int ss = 1000;
            int mi = ss * 60;
            int hh = mi * 60;
            int dd = hh * 24;

            long day = ms / dd;
            long hour = (ms - day * dd) / hh;
            long minute = (ms - day * dd - hour * hh) / mi;
            long second = (ms - day * dd - hour * hh - minute * mi) / ss;
            long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;

            string sDay = day < 10 ? "0" + day : "" + day; //天
            string sHour = hour < 10 ? "0" + hour : "" + hour;//小时
            string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟
            string sSecond = second < 10 ? "0" + second : "" + second;//秒
            string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒
            sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond;

            return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond);
        }

        /// <summary>
        /// 将string转换为DateTime，若转换失败，则返回日期最小值。不抛出异常。  
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private DateTime ParseToDateTime(string str)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(str))
                {
                    return DateTime.MinValue;
                }
                if (str.Contains("-") || str.Contains("/"))
                {
                    return DateTime.Parse(str);
                }
                else
                {
                    int length = str.Length;
                    switch (length)
                    {
                        case 4:
                            return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture);
                        case 6:
                            return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture);
                        case 8:
                            return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
                        case 10:
                            return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture);
                        case 12:
                            return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture);
                        case 14:
                            return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
                        default:
                            return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
                    }
                }
            }
            catch
            {
                return DateTime.MinValue;
            }
        }
    }




    public class MemoryMetrics
    {
        public double Total { get; set; }
        public double Used { get; set; }
        public double Free { get; set; }

  
    }

    public class MemoryMetricsClient
    {
        public bool IsUnix()
        {
            var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
            return isUnix;
        }

        public MemoryMetrics GetMetrics()
        {
            if (IsUnix())
            {
                return GetUnixMetrics();
            }
            return GetWindowsMetrics();
        }

        private MemoryMetrics GetWindowsMetrics()
        {
            string output = Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value");

            var lines = output.Trim().Split("\n");
            var freeMemoryParts = lines[0].Split("=", StringSplitOptions.RemoveEmptyEntries);
            var totalMemoryParts = lines[1].Split("=", StringSplitOptions.RemoveEmptyEntries);

            var metrics = new MemoryMetrics();
            metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
            metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);
            metrics.Used = metrics.Total - metrics.Free;

            return metrics;
        }

        private MemoryMetrics GetUnixMetrics()
        {
            string output = Bash("free -m");

            var lines = output.Split("\n");
            var memory = lines[1].Split(" ", StringSplitOptions.RemoveEmptyEntries);

            var metrics = new MemoryMetrics();
            metrics.Total = double.Parse(memory[1]);
            metrics.Used = double.Parse(memory[2]);
            metrics.Free = double.Parse(memory[3]);

            return metrics;
        }


        public string Bash(string command)
        {
            var escapedArgs = command.Replace("\"", "\\\"");
            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "/bin/bash",
                    Arguments = $"-c \"{escapedArgs}\"",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                }
            };
            process.Start();
            string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            process.Dispose();
            return result;
        }

        public string Cmd(string fileName, string args)
        {
            string output = string.Empty;

            var info = new ProcessStartInfo();
            info.FileName = fileName;
            info.Arguments = args;
            info.RedirectStandardOutput = true;

            using (var process = Process.Start(info))
            {
                output = process.StandardOutput.ReadToEnd();
            }
            return output;
        }
    }
}
